package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

type Student struct {
	Person
	School string
	//p Person
}

func dealPerson(per Person) {
	per.eat()

}

func dealPersonAddr(per *Person) {
	per.eat()
}

func dealStudent(stu Student) {
	stu.eat()
}

func dealStudentAddr(stu *Student) {
	stu.eat()
}

func (p Person) grow() {
	fmt.Println(p.Name + "生长")
	p.Age++
}

func (p Person) eat() {
	fmt.Println(p.Name + "吃")
}

type PersonI interface {
	grow()
	eat()
}

//PersonI传的p的类型与结构体方法定义有关，只要有一个方法处传指针，这里就只能传指针，方法处全都不是指针，这里就可传值也可传指针
func dealPersonI(p PersonI) {
	fmt.Printf("dealPersonI %T,%v\n", p, p)
	p.grow()
}

//这样写传的是指针的指针
func dealPersonIaddr(p *PersonI) {
	fmt.Printf("dealPersonAddr %T,%v\n", p, p)
	(*p).grow()
}

func main() {
	p := Person{
		Name: "zs",
		Age:  23,
	}
	s := Student{
		Person: Person{"张三", 15},
		School: "北京小学",
		//p: Person{"", 0},
	}
	dealPerson(p)
	dealPersonAddr(&p)
	dealStudent(s)
	dealStudentAddr(&s)
	p.grow()
	fmt.Println(p.Age) //age没有变化
	s.grow()
	fmt.Println(s.Age) //age没有变化

	dealPersonI(p)
	dealPersonI(s)
	fmt.Println(p.Age) //age没有变化
	fmt.Println(s.Age) //age没有变化
	//结构体类型转为接口类型，由于接口方法传递的都是值，没有指针，所以这里可以将值类型转为接口类型
	var pi PersonI = p
	var si PersonI = s
	fmt.Println(pi)
	fmt.Println(si)

	dealPersonI(pi)
	dealPersonIaddr(&pi)

	//接口类型转为结构体类型
	var p2 Person = pi.(Person)
	fmt.Println(p2)
	var s2 Student = si.(Student)
	fmt.Println(s2)
}
